#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include "jsoncpp/json.h"

namespace skyking
{
    using std::bitset;
    using std::cin;
    using std::cout;
    using std::endl;
    using std::ifstream;
    using std::ios;
    using std::istream;
    using std::istringstream;
    using std::map;
    using std::ofstream;
    using std::ostringstream;
    using std::setfill;
    using std::setiosflags;
    using std::setw;
    using std::string;
    using std::to_string;
    using std::unordered_map;
    using std::vector;
    using std::chrono::duration_cast;
    using std::chrono::microseconds;
    using std::chrono::steady_clock;

    int test1(unsigned short count)
    {
        map<string, unsigned short> m = {{"A", 5}, {"B", 5}};
        --(m["B"]);
        cout << m["B"] << endl;
        vector<unsigned short> v = {1, 2, 9, 3, 4, 9, 5, 6, 9, 7, 8};
        v.erase(find(v.begin(), v.end(), 9));
        for_each(v.cbegin(), v.cend(), [](const int &c) { cout << c << " "; });
        cout << endl;
        v.erase((++find(v.rbegin(), v.rend(), 9)).base());
        for_each(v.cbegin(), v.cend(), [](const int &c) { cout << c << " "; });
        cout << endl;
        return 0;
    }

    int test2()
    {
        // [0]_____w__h__d__s__t_ek_ck
        // [0]t0:_15_13__2__3__3__4__4
        // [0]my:_15_13__2__3__3__4__4
        // [0]t2:_15_13__2__3__3__4__4
        // [0]t3:_15_13__2__3__3__4__4
        ostringstream sum_tmp;
        // 生成单条日志(自带换行)
        sum_tmp.fill('_'); //设置填充方式
        sum_tmp << setiosflags(ios::left) << setw(3) << "99";
        sum_tmp << "__w__h__d__s__t_ek_ck" << endl;
        sum_tmp.setf(ios::right); //设置填充方式
        sum_tmp << "t"
                << "0"
                << ":";
        sum_tmp << setw(3) << "15";
        sum_tmp << setw(3) << "13";
        sum_tmp << setw(3) << "2";
        sum_tmp << setw(3) << "3";
        sum_tmp << setw(3) << "3";
        sum_tmp << setw(3) << "4";
        sum_tmp << setw(3) << "4";
        sum_tmp << endl;
        cout << sum_tmp.str() << endl;
        return 0;
    }

    void test3()
    {
        vector<int> r{1, 2, 3, 4};
        ostringstream a;
        for (int n : r)
            a << n << ",";
        a << endl;
        cout << a.str();
        a.str("");
        for (int n : r)
            a << n << ",";
        a << endl;
        cout << a.str();
    }

    Json::Value int_vector_to_json(vector<int> const &v)
    {
        Json::Value json_value;
        for_each(v.begin(), v.end(), [&json_value](int value) { json_value.append(value); });
        return json_value;
    }

    Json::Value int_map_to_json(map<int, int> const &m)
    {
        Json::Value json_value;
        for_each(m.begin(), m.end(), [&json_value](const auto &iter) { json_value[to_string(iter.first)] = iter.second; });
        return json_value;
    }

    void test4()
    {
        vector<int> v1{1, 2, 3};
        map<int, int> m1{
            {1, 1},
            {2, 2},
            {3, 3},
        };
        Json::Value j1;
        j1["v1"] = int_vector_to_json(v1);
        j1["m1"] = int_map_to_json(m1);
        cout << j1 << endl;
        Json::Value y;
        y["y"] = j1;
        cout << y << endl;
    }

#include <tuple>
#include <type_traits>

    namespace detail
    {

        template <typename Fn, typename Tuple, std::size_t... I>
        inline constexpr void ForEachTuple(Tuple &&tuple,
                                           Fn &&fn,
                                           std::index_sequence<I...>)
        {
            using Expander = int[];
            (void)Expander{0, ((void)fn(std::get<I>(std::forward<Tuple>(tuple))), 0)...};
        }

        template <typename Fn, typename Tuple>
        inline constexpr void ForEachTuple(Tuple &&tuple, Fn &&fn)
        {
            ForEachTuple(
                std::forward<Tuple>(tuple), std::forward<Fn>(fn),
                std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{});
        }

        template <typename T>
        struct is_field_pointer : std::false_type
        {
        };

        template <typename C, typename T>
        struct is_field_pointer<T C::*> : std::true_type
        {
        };

        template <typename T>
        constexpr auto is_field_pointer_v = is_field_pointer<T>::value;

    } // namespace detail

    template <typename T>
    inline constexpr auto StructSchema()
    {
        return std::make_tuple();
    }

#define DEFINE_STRUCT_SCHEMA(Struct, ...)        \
    template <>                                  \
    inline constexpr auto StructSchema<Struct>() \
    {                                            \
        using _Struct = Struct;                  \
        return std::make_tuple(__VA_ARGS__);     \
    }

#define DEFINE_STRUCT_FIELD(StructFieldName) \
    std::make_tuple(&_Struct::StructFieldName, #StructFieldName)

    template <typename T, typename Fn>
    inline constexpr void ForEachField(T &&value, Fn &&fn)
    {
        constexpr auto struct_schema = StructSchema<std::decay_t<T>>();
        static_assert(std::tuple_size<decltype(struct_schema)>::value != 0,
                      "StructSchema<T>() for type T should be specialized to return "
                      "FieldSchema tuples, like ((&T::field, field_name), ...)");

        detail::ForEachTuple(struct_schema, [&value, &fn](auto &&field_schema) {
            using FieldSchema = std::decay_t<decltype(field_schema)>;
            static_assert(
                std::tuple_size<FieldSchema>::value >= 2 &&
                    detail::is_field_pointer_v<std::tuple_element_t<0, FieldSchema>>,
                "FieldSchema tuple should be (&T::field, field_name)");

            fn(value.*(std::get<0>(std::forward<decltype(field_schema)>(field_schema))),
               std::get<1>(std::forward<decltype(field_schema)>(field_schema)));
        });
    }

    namespace
    {

        template <class... Fs>
        struct overload_set;

        template <class F1, class... Fs>
        struct overload_set<F1, Fs...> : F1, overload_set<Fs...>::type
        {
            typedef overload_set type;

            overload_set(F1 head, Fs... tail)
                : F1(head), overload_set<Fs...>::type(tail...) {}

            using F1::operator();
            using overload_set<Fs...>::type::operator();
        };

        template <class F>
        struct overload_set<F> : F
        {
            typedef F type;
            using F::operator();
        };

        template <class... Fs>
        typename overload_set<Fs...>::type overload(Fs... x)
        {
            return overload_set<Fs...>(x...);
        }

    } // namespace

    struct SimpleStruct
    {
        bool bool_data;
        int int_data;
        double double_data;
        unsigned short short_data;
        string string_data;
    } SimpleStruct_Default = {true, 1, 1.0, 666, "hello static reflection"};
    DEFINE_STRUCT_SCHEMA(
        SimpleStruct,
        DEFINE_STRUCT_FIELD(bool_data),
        DEFINE_STRUCT_FIELD(int_data),
        DEFINE_STRUCT_FIELD(double_data),
        DEFINE_STRUCT_FIELD(short_data));

    struct GenericFunctor
    {
        // ... context data
        template <typename Field, typename Name>
        void operator()(Field &&field, Name &&name)
        {
            cout << std::boolalpha << std::fixed << name << ": " << field
                 << endl;
        }
    };

    void test5()
    {
        SimpleStruct tmp = SimpleStruct_Default;
        Json::Value json_value;
        ForEachField(tmp,
                     overload(
                         [&json_value](unsigned short field, const char *name) {
                             json_value[name] = field;
                         },
                         [](const string &field, const char *name) {
                             cout << "s " << name << ": " << field.c_str()
                                  << endl;
                         }));
        cout << json_value << endl;
    }

    void bitset_2_string(const bitset<136> &set, string &str)
    {
        unsigned short index = 0;
        unsigned short set_size = set.size();
        for (int i = 0; i < set_size; i += 8)
        {
            char ch = 0;
            for (int j = 0; j < 8; ++j)
            {
                if (set.test(i + j)) // 第i + j位为1
                    ch |= (1 << j);
                else
                    ch &= ~(1 << j);
            }
            str[index++] = ch;
        }
    }
    void string_2_bitset(const string &str, bitset<136> &set)
    {
        unsigned short index = 0;
        unsigned short str_size = str.size();
        for (int i = 0; i < str_size; ++i)
        {
            char ch = str[i];
            int offset = i * 8;
            for (int j = 0; j < 8; ++j)
            {
                set.set(offset + j, ch & (1 << j)); // 第j位为是否为1
                ++index;
            }
        }
    }

    void test6()
    {
        bitset<136> set1;
        string str(17, char(0));
        cout << "before" << endl;
        cout << "set: " << set1.to_string() << endl;
        set1[2] = 1;
        set1[4] = 1;
        bitset_2_string(set1, str);
        bitset<136> set2;
        string_2_bitset(str, set2);
        cout << "after" << endl;
        cout << "set: " << set2.to_string() << endl;

        string a = "hello world";
        cout << a << endl;
        cout << a.size() << endl;
        a[5] = '\0';
        cout << a << endl;
        cout << a.size() << endl;
    }
    void test7()
    {
        bitset<5> set1;
        cout << set1.to_string() << endl;
        set1.set(1);
        string str = set1.to_string();
        cout << str << endl;
        set1 = bitset<5>(str);
        cout << set1.to_string() << endl;
    }
    void split(const string &s, vector<string> &tokens, char delim = ' ')
    {
        tokens.clear();
        auto string_find_first_not = [s, delim](size_t pos = 0) -> size_t {
            for (size_t i = pos; i < s.size(); i++)
            {
                if (s[i] != delim)
                    return i;
            }
            return string::npos;
        };
        size_t lastPos = string_find_first_not(0);
        size_t pos = s.find(delim, lastPos);
        while (lastPos != string::npos)
        {
            tokens.emplace_back(s.substr(lastPos, pos - lastPos));
            lastPos = string_find_first_not(pos);
            pos = s.find(delim, lastPos);
        }
    }
    void test8()
    {
        string s = "1,11,111;2,22,222";
        vector<string> tokens;
        split(s, tokens, ';');
        cout << tokens.size() << endl;
    }

    class A
    {
    protected :
        const int a_;

    public:
        explicit A(int a) : a_(a) {}
        virtual void print_a() { cout << a_ << endl; }
    };
    class B : virtual public A
    {
    protected :
        int b_ = 20;
    public:
        explicit B(int a) : A(a) {}
        void print_b() { cout << b_ << endl; }
    };
    class C : virtual protected A
    {
    protected :
        int c_ = 30;
    public:
        explicit C(int a) : A(a) {}
        void print_c() { cout << c_ << endl; }
    };
    class D : public B, public C
    {
    public:
        explicit D(int a) : A(9), B(8), C(7) {}
    };

    void test9()
    {
        D d(5);
        d.A::print_a();
        d.B::print_a();
        d.print_a();
        d.print_b();
        d.print_c();
        C c(5);
        c.print_c();
    }

    void test10()
    {
        bitset<3> a;
        a[0] = '0';
        string str = a.to_string();
        cout << a.to_string() << endl;
        cout << str.at(str.size()-1-0) << endl;
    }

} // namespace skyking

int main(int argc, char *argv[])
{
    skyking::test10();
    return 0;
}
